﻿/*******************************************************************************

    Units of Measure for C# applications

    Copyright (C) 2013 Marek Aniola

    This program is provided to you under the terms of the license
    as published at http://unitsofmeasure.codeplex.com/license


********************************************************************************/
using System;
using System.Globalization;

namespace Man.UnitsOfMeasure
{
	internal class HostDecimal : ITypeHost<decimal>
	{
		public decimal Zero { get { return 0.0M; } }
		public decimal Unity { get { return 1.0M; } }

		public decimal Negative(decimal x) { return -x; }

		public decimal Add(decimal x, decimal y) { return x + y; }
		public decimal Subtract(decimal x, decimal y) { return x - y; }
		public decimal Multiply(decimal x, decimal y) { return x * y; }
		public decimal Divide(decimal x, decimal y) { return x / y; }

		public decimal Pow(decimal x, int num, int den) { return (decimal)Math.Pow((double)x, (double)num / (double)den); }

		public bool Equal(decimal x, decimal y) { return x == y; }

		public int Compare(Quantity<decimal> x, Quantity<decimal> y)
		{
			return x.Value.CompareTo((x.Unit == y.Unit) ? y.Value : Calibrate(y, x.Unit));
		}

		public int Compare(Level<decimal> x, Level<decimal> y)
		{
			return x.Value.CompareTo((x.Unit == y.Unit) ? y.Value : Calibrate(y, x.Unit));
		}

		public decimal Calibrate(Quantity<decimal> q, Measure<decimal> target)
		{
			CheckDimensions(q.Unit, target);
			return (target.Scale / q.Unit.Scale) * q.Value;
		}

		public decimal Calibrate(Level<decimal> q, Measure<decimal> target)
		{
			CheckDimensions(q.Unit, target);
			return (target.Scale / q.Unit.Scale) * (q.Value - q.Unit.Shift) + target.Shift;
		}

		private static void CheckDimensions(Measure<decimal> x, Measure<decimal> y)
		{
			if (x.Sense != y.Sense) throw new InvalidOperationException(String.Format("Units \"{0}\" and \"{1}\" are of different dimensions.", x, y));
		}

		public bool TryParse(string input, NumberStyles style, IFormatProvider fp, out decimal result)
		{
			return decimal.TryParse(input, style, fp, out result);
		}
	}
}
